package gobase

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

var (
	ZeroTime      time.Time // UTC
	ZeroTimeLocal           = ZeroTime.Local()

	START_Time     time.Time     = StrToTimeDef("00", "04", time.UTC, ZeroTime)
	START_Duration time.Duration = ParseDuration("0s")

	secs_day  int64 = 60 * 60 * 24
	secs_hour int64 = 60 * 60

	minutes_per_day int64 = 60 * 24

	UnixZeroTime time.Time = time.Unix(0, 0).Local() // 默认是Local
)

const (
	secondsPerMinute int64 = 60
	secondsPerHour         = 60 * secondsPerMinute
	secondsPerDay          = 24 * secondsPerHour
	secondsPerWeek         = 7 * secondsPerDay
	daysPer400Years        = 365*400 + 97
	daysPer100Years        = 365*100 + 24
	daysPer4Years          = 365*4 + 1

	DURA_DAY time.Duration = time.Hour * 24
)

/*
**

	a:0时, f(a+6):6时, (a+23):23时,
*/
func ToHourChr(atime time.Time) string {
	h := atime.Hour()
	i := int(rune('a'))
	rval := string(rune(i + h))
	return rval
}

/*
**

	A:0时, F(A+6):6时, (A+23):23时,
*/
func ToHourChrUpcase(atime time.Time) string {
	h := atime.Hour()
	i := int(rune('A'))
	rval := string(rune(i + h))
	return rval
}

func MaxTime(t0 time.Time, t1 time.Time) time.Time {
	if !t0.Before(t1) {
		return t0
	} else {
		return t1
	}
}

func MinTime(t0 time.Time, t1 time.Time) time.Time {
	if t0.IsZero() {
		return t1
	}
	if !t0.After(t1) {
		return t0
	} else {
		return t1
	}
}

/*
*

	FixIntervalLastTime("2020-06-05 13:13:29", time.Minute * 15) = 2020-06-05 13:00:00
*/
func FixintervalLastTime(t time.Time, fixinterval time.Duration) time.Time {
	n := int64(math.Floor(float64(t.Unix()) / fixinterval.Seconds()))
	secN := n * int64(fixinterval.Seconds())
	t1 := time.Unix(secN, 0)
	return LocationCopy(t1, t)
}

/*
**

	loctime 不能为 ZeroTime
*/
func LocationCopy(t1, loctime time.Time) time.Time {
	if loctime == ZeroTime {
		return t1.Local() // 转成Location
	}

	if loctime.IsZero() {
		return t1.UTC() // 转成Location
	}

	if TimeIsUnixZero(loctime) {
		if loctime == UnixZeroTime {
			return t1.Local() // 转成Location
		} else {
			return t1.UTC()
		}
	}

	return loctime.Add(t1.Sub(loctime))
}

/*
**

	判断t是否是Unix的起始时间或者之前.
	返回为true表示该时间无效
*/
func TimeIsUnixZero(t time.Time) bool {
	if t.IsZero() {
		return true
	}

	return t.Unix() <= UnixZeroTime.Unix()
}

/*
*

	FixIntervalNextTime("2020-06-05 13:13:29", time.Minute * 15) = 2020-06-05 13:15:00
*/
func FixintervalNextTime(t time.Time, fixinterval time.Duration) time.Time {
	n := int64(math.Ceil(float64(t.Unix()) / fixinterval.Seconds()))
	secN := n * int64(fixinterval.Seconds())
	t1 := time.Unix(secN, 0)
	return LocationCopy(t1, t)
}

/*
*

	精确到毫秒
*/
func TimeBetween(t0 time.Time, start time.Time, end time.Time) bool {
	if start.IsZero() && end.IsZero() {
		return true
	}
	unixms := t0.UnixMilli()
	startok := start.IsZero() || unixms >= start.UnixMilli()
	if !startok {
		return false
	}
	return end.IsZero() || unixms <= end.UnixMilli()
}

func RoundTime_Second(t time.Time) time.Time {
	unixNano := t.UnixNano()
	secs := int64((float64(unixNano) / float64(time.Second)) + 0.5)
	t1 := time.Unix(secs, 0)
	return LocationCopy(t1, t)
}

/*
*

	FixintervalOffsetTime("2020-06-05 13:13:29", time.Minute * 15, 0) = 2020-06-05 13:00:00
*/
func FixintervalOffsetTime(t time.Time, fixinterval time.Duration, offsetN int) time.Time {
	intervalSecN := int64(fixinterval.Seconds())

	n := t.Unix() / intervalSecN
	secN := n*intervalSecN + int64(offsetN)*intervalSecN
	t1 := time.Unix(secN, 0)
	return LocationCopy(t1, t)
	//return t;

	//if t.Location() != t1.Location(){

	//return time.Date(t1.Year(), t1.Month(), t1.Day(), t1.Hour(), t1.Minute(), t1.Second(), t1.Nanosecond(), t.Location())
	//}
	//return t1
}

func ParseDurationEx(s string, def time.Duration) time.Duration {
	s1, s2 := SplitQuantifiersUnits(s)
	v, err := strconv.ParseFloat(s1, 64)
	if err != nil {
		return def
	}

	// 默认使用秒
	if s2 == "S" || s2 == "s" || s2 == "秒" || len(s2) == 0 {
		return time.Duration(v * float64(time.Second))
	}

	if s2 == "ms" || s2 == "MS" || s2 == "毫秒" {
		return time.Duration(v * float64(time.Millisecond))
	}

	if s2 == "m" || s2 == "M" || s2 == "分" || s2 == "分钟" {
		return time.Duration(v * float64(time.Minute))
	}

	if s2 == "h" || s2 == "H" || s2 == "时" || s2 == "小时" {
		return time.Duration(v * float64(time.Hour))
	}

	s2 = strings.ToLower(s2)

	if s2 == "d" || s2 == "day" || s2 == "天" {
		return time.Duration(v * float64(DURA_DAY))
	}

	if s2 == "w" || s2 == "week" || s2 == "周" {
		return time.Duration(v * float64(DURA_DAY*7))
	}

	if s2 == "month" || s2 == "月" || s2 == "个月" {
		return time.Duration(v * float64(DURA_DAY*30))
	}

	if s2 == "y" || s2 == "year" || s2 == "年" {
		return time.Duration(v * float64(DURA_DAY*366))
	}
	return def
}

func ParseDuraStr(s string) time.Duration {
	s1, s2 := SplitQuantifiersUnits(s)
	if strings.Contains(s2, "月") {
		return time.Duration(StrToIntDef(s1, 1)) * DURA_DAY * 30
	} else if strings.Contains(s2, "年") {
		return time.Duration(StrToIntDef(s1, 1)) * DURA_DAY * 365
	} else if strings.Contains(s2, "天") {
		return time.Duration(StrToIntDef(s1, 1)) * DURA_DAY
	} else if strings.Contains(s2, "时") {
		return time.Duration(StrToIntDef(s1, 1)) * time.Hour
	} else if strings.Contains(s2, "分") {
		return time.Duration(StrToIntDef(s1, 1)) * time.Minute
	} else if strings.Contains(s2, "秒") {
		return time.Duration(StrToIntDef(s1, 1)) * time.Second
	}

	return 0
}

func ParseDuration(timeExp string) time.Duration {
	rval, err := time.ParseDuration(timeExp)
	if err == nil {
		return rval
	}

	exp_l := len(timeExp)
	if exp_l == 5 {
		t1, err := time.Parse("15:04", timeExp)
		if err != nil {
			return 0
		}
		return t1.Sub(START_Time)
	}

	if exp_l == 8 {
		t1, err := time.Parse("15:04:05", timeExp)
		if err != nil {
			return 0
		}
		return t1.Sub(START_Time)
	}

	if exp_l == 4 {
		t1, err := time.Parse("1504", timeExp)
		if err != nil { // 8:00
			t1, err = time.Parse("15:04", timeExp)
		}

		if err != nil {
			return 0
		}
		return t1.Sub(START_Time)
	}

	if exp_l == 2 {
		t1, err := time.Parse("15", timeExp)
		if err != nil {
			return 0
		}
		return t1.Sub(START_Time)
	}

	return 0
}

func DayOfYear(atime time.Time) string {
	v := atime.YearDay()
	return fmt.Sprintf("%.3d", v)
}

func ParseTimeFmt(strPattern string, _t time.Time) string {
	strPattern = ReplacePlaceholder(strPattern, "#", "#", func(key string) (v string, ok bool) {
		return GetDateTimeKeyValue(key, _t)
	})

	strPattern = ReplacePlaceholder(strPattern, "$", "$", func(key string) (v string, ok bool) {
		return GetDateTimeKeyValue(key, _t)
	})
	return strPattern
	//mi := _t.Minute()
	//qua := mi / 15 * 15
	//m5 := mi / 5 * 5
	//m10 := mi / 10 * 10
	//strQua := fmt.Sprintf("%.2d", qua)
	//strM5 := fmt.Sprintf("%.2d", m5)
	//strM10 := fmt.Sprintf("%.2d", m10)
	//strPattern = strings.Replace(strPattern, "$yyyy$", _t.Format("2006"), -1)
	//strPattern = strings.Replace(strPattern, "#yyyy#", _t.Format("2006"), -1)
	//strPattern = strings.Replace(strPattern, "$yy$", _t.Format("06"), -1)
	//strPattern = strings.Replace(strPattern, "#yy#", _t.Format("06"), -1)
	//strPattern = strings.Replace(strPattern, "$mm$", _t.Format("01"), -1)
	//strPattern = strings.Replace(strPattern, "#mm#", _t.Format("01"), -1)
	//strPattern = strings.Replace(strPattern, "$dd$", _t.Format("02"), -1)
	//strPattern = strings.Replace(strPattern, "#dd#", _t.Format("02"), -1)
	//strPattern = strings.Replace(strPattern, "$hh$", _t.Format("15"), -1)
	//strPattern = strings.Replace(strPattern, "#hh#", _t.Format("15"), -1)
	//strPattern = strings.Replace(strPattern, "$mi$", _t.Format("04"), -1)
	//strPattern = strings.Replace(strPattern, "#mi#", _t.Format("04"), -1)
	//strPattern = strings.Replace(strPattern, "#ss#", _t.Format("05"), -1)
	//strPattern = strings.Replace(strPattern, "$ss$", _t.Format("05"), -1)
	//
	//strPattern = strings.Replace(strPattern, "$doy$", DayOfYear(_t), -1)
	//strPattern = strings.Replace(strPattern, "#doy#", DayOfYear(_t), -1)
	//
	//strPattern = strings.Replace(strPattern, "$hc$", ToHourChr(_t), -1)
	//strPattern = strings.Replace(strPattern, "#hc#", ToHourChr(_t), -1)
	//strPattern = strings.Replace(strPattern, "$HC$", ToHourChrUpcase(_t), -1)
	//strPattern = strings.Replace(strPattern, "#HC#", ToHourChrUpcase(_t), -1)
	//
	//strPattern = strings.Replace(strPattern, "#qu#", strQua, -1)
	//strPattern = strings.Replace(strPattern, "$qu$", strQua, -1)
	//
	//strPattern = strings.Replace(strPattern, "#m5#", strM5, -1)
	//strPattern = strings.Replace(strPattern, "$m5$", strM5, -1)
	//
	//strPattern = strings.Replace(strPattern, "#m10#", strM10, -1)
	//strPattern = strings.Replace(strPattern, "$m10$", strM10, -1)
	//
	//strPattern = strings.Replace(strPattern, "#timeid#", _t.Format("150405"), -1)
	//strPattern = strings.Replace(strPattern, "$timeid$", _t.Format("150405"), -1)

	return strPattern
}

func HumanDuration(dura time.Duration) string {
	return HumanTimeStr(int64(dura.Seconds()))
}

func HumanTimeStr(secs int64) string {

	r := secs

	if r == 0 {
		return "0秒"
	}

	v := r / secs_day
	str := ""
	if v > 0 {
		str += fmt.Sprintf(" %d天", v)
	}
	r = r % secs_day

	v = r / secs_hour
	if v > 0 {
		str += fmt.Sprintf(" %d时", v)
	}
	r = r % secs_hour

	v = r / 60
	if v > 0 {
		str += fmt.Sprintf(" %d分", v)
	}
	r = r % 60

	if r > 0 {
		str += fmt.Sprintf(" %d秒", r)
	}

	return Trim(str)

}

func HumanTimeStrFromMinutesInt(minutes int, spliter string) string {
	return HumanTimeStrFromMinutes(int64(minutes), spliter)

}

func HumanTimeStrFromMinutes(minutes int64, spliter string) string {

	r := minutes

	v := r / minutes_per_day
	var sb BytesBuilder
	if v > 0 {
		sb.Appendf("%d天", v)
	}
	r = r % minutes_per_day

	v = r / 60
	if v > 0 {
		if sb.Len() > 0 {
			sb.AppendStr(spliter)
		}
		sb.Appendf("%d时", v)

	}
	r = r % 60

	if r > 0 {
		if sb.Len() > 0 {
			sb.AppendStr(spliter)
		}
		sb.Appendf("%d分", r)
	}

	if sb.Len() == 0 {
		return "0分"
	}

	return sb.String()

}

// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the
// tail of buf, omitting trailing zeros. It omits the decimal
// point too when the fraction is 0. It returns the index where the
// output bytes begin and the value v/10**prec.
func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) {
	// Omit trailing zeros up to and including decimal point.
	w := len(buf)
	print := false
	for i := 0; i < prec; i++ {
		digit := v % 10
		print = print || digit != 0
		if print {
			w--
			buf[w] = byte(digit) + '0'
		}
		v /= 10
	}
	if print {
		w--
		buf[w] = '.'
	}
	return w, v
}

// fmtInt formats v into the tail of buf.
// It returns the index where the output begins.
func fmtInt(buf []byte, v uint64) int {
	w := len(buf)
	if v == 0 {
		w--
		buf[w] = '0'
	} else {
		for v > 0 {
			w--
			buf[w] = byte(v%10) + '0'
			v /= 10
		}
	}
	return w
}

func HexToDateTime(hex string, def time.Time) time.Time {
	v, err := strconv.ParseInt(hex, 16, 32)
	if err != nil {
		return def
	}
	return time.Unix(v, 0)
}

// StatusString returns a string representing the duration in the form "72h3m0.5s".
// Leading zero units are omitted. As a special case, durations less than one
// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure
// that the leading digit is non-zero. The zero duration formats as 0s.
// 去掉了秒的小数
func DurationStr(d time.Duration) string {
	// Largest time is 2540400h10m10.000000000s
	var buf [32]byte
	w := len(buf)

	u := uint64(d)
	neg := d < 0
	if neg {
		u = -u
	}

	if u < uint64(time.Second) {
		// Special case: if duration is smaller than a second,
		// use smaller units, like 1.2ms
		var prec int
		w--
		buf[w] = 's'
		w--
		switch {
		case u == 0:
			return "0s"
		case u < uint64(time.Microsecond):
			// print nanoseconds
			prec = 0
			buf[w] = 'n'
		case u < uint64(time.Millisecond):
			// print microseconds
			prec = 3
			// U+00B5 'µ' micro sign == 0xC2 0xB5
			w-- // Need room for two bytes.
			copy(buf[w:], "µ")
		default:
			// print milliseconds
			prec = 6
			buf[w] = 'm'
		}
		w, u = fmtFrac(buf[:w], u, prec)
		w = fmtInt(buf[:w], u)
	} else {
		// 大于 秒

		// 去除秒后面的小数
		u = u / uint64(time.Second) * uint64(time.Second)

		w--
		buf[w] = 's'

		w, u = fmtFrac(buf[:w], u, 9)

		// u is now integer seconds
		w = fmtInt(buf[:w], u%60)
		u /= 60

		// u is now integer minutes
		if u > 0 {
			w--
			buf[w] = 'm'
			w = fmtInt(buf[:w], u%60)
			u /= 60

			// u is now integer hours
			// Close at hours because days can be different lengths.
			if u > 0 {
				w--
				buf[w] = 'h'
				w = fmtInt(buf[:w], u)
			}
		}
	}

	if neg {
		w--
		buf[w] = '-'
	}

	return string(buf[w:])
}

func ToUTCTime(src time.Time) time.Time {
	return src.UTC()
}

func NowString() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

func NowStringEx() string {
	return time.Now().Format("2006-01-02 15:04:05.999")
}

func NowIDString() string {
	return time.Now().Format("060102150405")
}

func TodayStr() string {
	return time.Now().Format("2006-01-02")
}

func TodayIDString() string {
	return time.Now().Format("060102")
}

func DateTimeIDString(val time.Time) string {
	return val.Format("060102150405")
}

func DateTimeString(val time.Time) string {
	return val.Format("2006-01-02 15:04:05")
}

func DateString(val time.Time) string {
	return val.Format("2006-01-02")
}

func DateYYMM(val time.Time) string {
	return val.Format("0601")
}

func DateYYYYMM(val time.Time) string {
	return val.Format("200601")
}

func DateYYYYMMDD(val time.Time) string {
	return val.Format("20060102")
}

func IsSameDay(time1, time2 time.Time) bool {
	y1, m1, d1 := time1.Date()
	y2, m2, d2 := time2.Date()
	return d1 == d2 && m1 == m2 && y1 == y2
}

func IsSameMonth(time1, time2 time.Time) bool {
	y1, m1, _ := time1.Date()
	y2, m2, _ := time2.Date()
	return m1 == m2 && y1 == y2
}

/***
 * 如果时间为空，则返回""
 */
func DateTimeString2(val time.Time) string {
	if val.IsZero() {
		return ""
	} else {
		return val.Format("2006-01-02 15:04:05")
	}
}

func DateTimeString3(val time.Time) string {
	if val.IsZero() {
		return ""
	} else {
		return val.Format("2006-01-02 15:04:05.999")
	}
}

func TimeString3(val time.Time) string {
	if val.IsZero() {
		return ""
	} else {
		return val.Format("15:04:05.999")
	}
}

func DateTimeStringForShow(val time.Time) string {
	if val.IsZero() {
		return ""
	} else {
		return val.Format("01-02 15:04")
	}
}

func DateTimeStringForShortShow(val time.Time) string {
	if val.IsZero() {
		return ""
	} else {
		return val.Format("0102 15:04:05")
	}
}

func GetDayOfWeek(val time.Time) byte {
	return byte(val.Weekday())
}

func TimeInUtcToday(val time.Time) time.Duration {
	return time.Duration(val.Unix()%secondsPerDay) * time.Second
}

func TimeInLocalToday(val time.Time) time.Duration {
	str := val.Local().Format("15:04")
	rval := ParseDuration(str)

	//_, offset := val.Zone();
	//ral := (time.Duration(val.Unix() % secondsPerDay) + time.Duration(offset)) * time.Second;
	//if ral.Hours() > 24 {
	//	ral = ral - time.Hour * 24;
	//}
	return rval
}

func TryStrToBool(str string, def bool) bool {
	if len(str) == 0 {
		return def
	}

	return str == "true" || str == "TRUE" || str == "1" || str == "YES" || str == "yes" || str == "是"
}

func StrToTimeDef(str, format string, location *time.Location, def time.Time) time.Time {
	if len(str) == 0 {
		return def
	}
	rval, err := time.ParseInLocation(format, str, location)
	if err == nil {
		return rval
	}
	return def
}

func TryStrToTimeDefZero(str string, location *time.Location) (rval time.Time) {
	rval = TryStrToTime(str, location, rval)
	return
}

func BetweenTime(t0, startTime, endTime time.Time) bool {
	ok := true
	if !startTime.IsZero() {
		ok = t0.After(startTime)
	}

	if ok && !endTime.IsZero() {
		ok = t0.Before(endTime)
	}
	return ok
}

func TryStrToTime(str string, location *time.Location, def time.Time) time.Time {
	if len(str) == 0 {
		return def
	}

	strl := len(str)
	var rval time.Time
	var err error
	if strl == 19 {
		rval, err = time.ParseInLocation("2006-01-02 15:04:05", str, location)
		if err == nil {
			return rval
		}

		rval, err = time.ParseInLocation("2006/01/02 15:04:05", str, location)
		if err == nil {
			return rval
		}
		rval, err = time.ParseInLocation("2006-01-02/15:04:05", str, location)
		if err == nil {
			return rval
		}

		rval, err = time.ParseInLocation("2006 01 02 15 04 05", str, location)
		if err == nil {
			return rval
		}

	}

	rval, err = time.ParseInLocation("2006-01-02 15:04:05.999", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("2006-01-02T15:04:05Z", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("2006/1/2 15:4:5", str, location)
	if err == nil {
		return rval
	}
	rval, err = time.ParseInLocation("2006-1-2 15:4:5", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("20060102150405", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("2006/01/02", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("2006/1/2", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("2006-01-02", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("2006-1-2", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("20060102", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("15:04:05", str, location)
	if err == nil {
		return rval
	}

	rval, err = time.ParseInLocation("15:04", str, location)
	if err == nil {
		return rval
	}

	return def
}

func SecondOf(start time.Time, end time.Time) int64 {
	if start.IsZero() {
		return 0
	}

	if end.IsZero() {
		return 0
	}
	t1 := start.Unix()
	t2 := end.Unix()

	return t2 - t1
}

func MSecOfDuration(time time.Duration) int64 {
	return int64(time / 1e6)
}

//func BetweenTime(t1, t2 time.Time) time.Duration {
//	if t1.After(t2) {
//		return t1.Sub(t2)
//	} else {
//		return t2.Sub(t1)
//	}
//}

func AbsDuration(t1 time.Duration) time.Duration {
	if t1 < 0 {
		return -t1
	} else {
		return t1
	}
}

func SecondBetween(t1, t2 time.Time) float64 {
	return math.Abs(float64(t2.UnixNano()-t1.UnixNano()) / float64(time.Second)) // 转成秒
}

func SecondSub(start, end time.Time) float64 {
	return float64(end.UnixNano()-start.UnixNano()) / float64(time.Second) // 转成秒
}

func MillisecondOf(start, end time.Time) int64 {
	return (end.UnixNano() - start.UnixNano()) / 1e6 // 转成毫秒
}

func MinuteOfDuration(time time.Duration) int64 {
	return int64(time / (1e9 * 60))
}

func IsLeapYear(year int) bool {
	return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}

func NextMonthV(month int) int {
	v := month + 1
	if v > 12 {
		v = 1
	}
	return v
}

func NextMonthYM(y, m int) (y1, m1 int) {
	y1 = y
	m1 = m + 1
	if m1 > 12 {
		m1 = 1
		y1++
	}
	return
}

func GetMonthDayN(year, month int) int {
	switch month {
	case 1, 3, 5, 7, 8, 10, 12:
		return 31
	case 4, 6, 9, 11:
		return 30
	case 2:
		if IsLeapYear(year) {
			return 29
		}
		return 28
	}
	return 0
}

func EndOfADay(day time.Time) time.Time {
	return time.Date(day.Year(), day.Month(), day.Day(), 23, 59, 59, 0, day.Location())
}

func StartOfADay(day time.Time) time.Time {
	return time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, day.Location())
}

func StartOfAMonth(day time.Time) time.Time {
	return time.Date(day.Year(), day.Month(), 1, 0, 0, 0, 0, day.Location())
}

func IncMonth(atime time.Time, num int) time.Time {
	return atime.AddDate(0, num, 0)
}

func IncDay(atime time.Time, num int) time.Time {
	if num == 0 {
		return atime
	}
	return atime.AddDate(0, 0, num)
}

func IncYear(atime time.Time, num int) time.Time {
	return atime.AddDate(num, 0, 0)
}

func SOD(atime time.Time) float64 {
	return atime.Sub(StartOfADay(atime)).Seconds()
}

func JoinDateAndTimeStr(dateT time.Time, timestr string) time.Time {
	l := len(timestr)
	if l == 6 {
		// 150405
		return JoinDateAndTimeStrFormat(dateT, timestr, "150405")
	}
	if l == 4 {
		// 1504
		//sp := string([]byte(timestr)[2])
		return JoinDateAndTimeStrFormat(dateT, timestr, "1504")
	}
	if l == 5 {
		// 15:04
		// 15 04
		sp := string([]byte(timestr)[2])
		return JoinDateAndTimeStrFormat(dateT, timestr, fmt.Sprintf("15%s04", sp))
	}

	if l == 8 {
		// 15:04:05
		// 15 04 05
		sp := string([]byte(timestr)[2])
		return JoinDateAndTimeStrFormat(dateT, timestr, fmt.Sprintf("15%s04%s05", sp, sp))
	}

	if l == 10 {
		// 150405.999

		return JoinDateAndTimeStrFormat(dateT, timestr, "150405.999")
	}

	if l == 12 {
		//15:04:05.999
		sp := string([]byte(timestr)[2])
		return JoinDateAndTimeStrFormat(dateT, timestr,
			fmt.Sprintf("15%s04%s05.999", sp, sp))
	}

	return time.Date(dateT.Year(), dateT.Month(), dateT.Day(), 0, 0, 0, 0, dateT.Location())
}

func JoinDateAndTimeStrFormat(dateT time.Time, timestr, timestr_format string) time.Time {
	t1 := StrToTimeDef(timestr, timestr_format, time.Local, UnixZeroTime.UTC())
	return JoinDateAndTime(dateT, t1)
}

func JoinDateAndTime(dateT, timeT time.Time) time.Time {
	return time.Date(dateT.Year(), dateT.Month(), dateT.Day(), timeT.Hour(), timeT.Minute(), timeT.Second(), timeT.Nanosecond(), dateT.Location())
}

func GetDateTimeKeyValue(key string, _t time.Time) (v string, ok bool) {
	s1, s2 := Split2Str(key, ":")
	if len(s1) > 0 {
		if s1 == "u" || s1 == "utc" {
			_t = _t.UTC()
			key = s2
		}
	}
	if key == "yyyy" {
		return _t.Format("2006"), true
	} else if key == "yy" {
		return _t.Format("06"), true
	} else if key == "mm" {
		return _t.Format("01"), true
	} else if key == "dd" {
		return _t.Format("02"), true
	} else if key == "yyyymmdd" {
		return _t.Format("20060602"), true
	} else if key == "hh" {
		return _t.Format("15"), true
	} else if key == "mi" {
		return _t.Format("04"), true
	} else if key == "ss" {
		return _t.Format("05"), true
	} else if key == "doy" {
		return DayOfYear(_t), true
	} else if key == "HC" {
		return ToHourChrUpcase(_t), true
	} else if key == "hc" {
		return ToHourChr(_t), true
	} else if key == "qu" || key == "m15" {
		mi := _t.Minute()
		qua := mi / 15 * 15
		strQua := fmt.Sprintf("%.2d", qua)
		return strQua, true
	} else if key == "m5" {
		mi := _t.Minute()
		v0 := mi / 5 * 5
		str := fmt.Sprintf("%.2d", v0)
		return str, true
	} else if key == "m10" {
		mi := _t.Minute()
		v0 := mi / 10 * 10
		str := fmt.Sprintf("%.2d", v0)
		return str, true
	} else if key == "timeid" {
		return _t.Format("150405"), true
	}
	return "", false
}
